using CfgTable;
using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using System.Collections.Generic;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public class SmallPetEntity : TViewReusableEntity
    {
        #region Fields

        /// <summary>
        /// 对象池的GameObject实体
        /// </summary>
        private Entity _objectEntity;

        private TransformAgent _transform;

        private CfgPhysicalEntity _cfgEntity;
        /// <summary>
        /// gameObject下名为"model"的子节点
        /// </summary>
        private Transform _modelTransform;
        private AnimatorAgent _animator;

        #endregion

        #region Properties

        //TViewEntity overrides
        public override int id => 0;
        public override int mcid => 0;
        public override int mapSymbolCid => 0;
        public override TransformAgent transform => _transform;
        public override string name => owner.name + "_smallpet";
        public override int viewRange => owner.viewRange;
        public override int viewAngle => owner.viewAngle;
        public override float defaultMeterSpeed => _cfgEntity.DefaultSpeed;
        public override Vector3 unityPosOfData => Vector3.zero;
        public override Quaternion unityRotationOfData => Quaternion.identity;
        public override CfgPhysicalEntity cfgEntity => _cfgEntity;
        public override TNavigationController navigationCtrl => owner.navigationCtrl;
        public override IReadOnlyList<int> offeredQuests => null;

        //TViewReusableEntity overrides
        public override uint MaxStore => 20;

        //property of mine
        public GameObject gameObject => _transform.gameObject;
        public TViewEntity owner { protected set; get; }
        public EntityBindPointSmallPetType bindPointType { get; private set; }

        #endregion

        #region Entity Create

        public static SmallPetEntity CreateEntity(TViewEntity owner, int pointId,
            int physicalEntityCid)
        {
            var entity = ClassPool<SmallPetEntity>.Get();
            entity.owner = owner;
            entity.bindPointType = (EntityBindPointSmallPetType)pointId;
            entity.EntityAddComponents();
            entity.RefreshDisplay(physicalEntityCid);
            return entity;
        }

        private void EntityAddComponents()
        {
            AddComponentWithPool<SmallPetMoveComponent>(ETComponentType.SmallPetMoveComponent);
            AddComponentWithPool<SmallPetAnimationComponent>(ETComponentType.SmallPetAnimationComponent);
        }

        private void RefreshDisplay(int physicalEntityCid)
        {
            if (physicalEntityCid <= 0 || _cfgEntity?.Id == physicalEntityCid)
            {
                return;
            }

            TryHideEntity();
            _cfgEntity = TableCenter.physicalEntity.Get(physicalEntityCid);
            LoadAndInstantiate().Forget();
        }

        private async UniTask LoadAndInstantiate()
        {
            var entityResPath = GetEntityLoadPath();
            _objectEntity = ManagerCenter.Entity.Get(entityResPath, (int)EntityPoolGroupType.SmallPetEntity);
            var state = await _objectEntity.Load();

            if (_objectEntity.gameObject == null)
            {
                return;
            }

            var gameObject = _objectEntity.gameObject;
#if UNITY_EDITOR
            gameObject.name = $"[SmallPet]{System.IO.Path.GetFileNameWithoutExtension(entityResPath)}";
#endif
            _transform = ClassPool.Get<TransformAgent>();
            _transform.Value = gameObject.transform;
            _transform.SetParent(owner.transform.parent, false);
            _transform.position = owner.transform.position;

            _modelTransform = _transform.Find("model");
            if (_modelTransform == null)
            {
                _modelTransform = _transform;
            }

            var entityDriver = gameObject.GetComponent<EntityDriver>();
            if (entityDriver != null)
            {
                entityDriver.defaultAudioSheet = _cfgEntity.DefaultAudioSheet;
            }

            //广播事件
            BroadcastComponentEvent(TComponentEvent.OnEntityObjectLoaded, state);
        }

        private string GetEntityLoadPath()
        {
            return PathConstant.GetEntityLevelPrefabPath(_cfgEntity.EntityAsset);
        }

        #endregion

        private void BroadcastComponentEvent<T>(TComponentEvent eventType, T arg)
        {
            foreach (var kv in componentMap)
            {
                if (kv.Value is TViewComponent component)
                {
                    component.OnComponentEvent(eventType, arg);
                }
            }
        }

        private void BroadcastComponentEvent(TComponentEvent eventType)
        {
            BroadcastComponentEvent(eventType, 0);
        }

        #region TViewReusableEntity Implement

        public override AnimatorAgent GetAnimator()
        {
            if (_animator != null)
            {
                return _animator;
            }
            _animator = ClassPool<SyncAnimatorExceptMove>.Get();
            InitAnimator(_animator as SyncAnimatorExceptMove);
            return _animator;
        }

        private void InitAnimator(SyncAnimatorExceptMove animator)
        {
            var anim = _modelTransform.GetComponent<Animator>();
            if (anim == null)
            {
                return;
            }
            animator.animator = anim;
            var ownerAnim = owner?.GetComponent<EntityAnimationComponent>(ETComponentType.EntityAnimation);
            if (ownerAnim == null || ownerAnim.animator == null || (ownerAnim.animator is not EventAnimator sourceAnim))
            {
                return;
            }
            animator.Subscribe(sourceAnim);
        }

        //小宠物无需跟服务器同步位置,直接不实现
        public override void UpdatePosToData(Vector3 position)
        {
        }

        public override void OnReset()
        {
            _modelTransform = null;
            if (_transform != null)
            {
                ClassPool.PutAutoType(_transform);
                _transform = null;
            }
            if (_animator != null)
            {
                ClassPool.PutAutoType(_animator);
                _animator = null;
            }
            owner = null;
            _cfgEntity = null;
            bindPointType = EntityBindPointSmallPetType.None;
        }

        private void TryHideEntity()
        {
            if (_objectEntity == null) return;
            ManagerCenter.Entity.HideEntity(_objectEntity);
            _objectEntity = null;
            BroadcastComponentEvent(TComponentEvent.OnEntityObjectHided);
        }

        public override void Free()
        {
            TryHideEntity();
            base.Free();
        }

        #endregion
    }
}